package procsim;

import java.util.*;
import java.awt.*;
import java.awt.image.*;

public class GSignal extends Signal implements GraphicalLine {

    private LinkedHashMap<Coords, ImageObserver> coords;
    private boolean displayName = false;

    public GSignal(int value){
        super(value);
        coords = new LinkedHashMap<Coords, ImageObserver>();
    }

    public GSignal(int value, boolean display){
        super(value);
        coords = new LinkedHashMap<Coords, ImageObserver>();
        displayName = display;
    }

    public GSignal(int value, String name){
        super(value, name);
        coords = new LinkedHashMap<Coords, ImageObserver>();
    }

    public GSignal(int value, String name, boolean display){
        super(value, name);
        coords = new LinkedHashMap<Coords, ImageObserver>();
        displayName = display;
    }

    public Color getColor(){
        if(isNull()) return Color.BLUE;
        else return Color.RED;
    }

    @Override
    public GSignal addCoords(ImageObserver observer, Coords coor){
        coords.put(coor, observer);
        return this;
    }

    @Override
    public GSignal addCoords(ImageObserver observer, int x1, int y1, int x2, int y2){
        coords.put(new Coords(x1, y1, x2, y2), observer);
        return this;
    }

    @Override
    public void drawIt(Graphics2D g, ImageObserver observer) {
        Util.saveGraphics(g);
        ArrayList<Coords> prevcoords = new ArrayList<Coords>();
        Iterator iter = coords.keySet().iterator();
        while(iter.hasNext()) {
            Coords drawing = (Coords)iter.next();
            ImageObserver tmp = coords.get(drawing);
            if(tmp!=observer) continue;
            g.setColor(getColor());
            g.drawLine(drawing.getX1(), drawing.getY1(), drawing.getX2(), drawing.getY2());
            prevcoords.add(drawing);
            if(displayName && writeName(drawing, prevcoords)){
                g.setColor(new Color(70, 70, 70));
                g.setFont(new Font("Arial", Font.PLAIN, 10));
                if(drawing.getX1() > drawing.getX2() || drawing.getY1() > drawing.getY2()){
                    if(drawing.getX1() - drawing.getX2() < drawing.getY1() - drawing.getY2())
                        g.drawString(getName(), drawing.getX1()+2 , drawing.getY1()-5);
                    else g.drawString(getName(), drawing.getX1()-5-3*(getName().length()+2), drawing.getY1()-1);
                }
                else{
                    if(drawing.getX2() - drawing.getX1() < drawing.getY2() - drawing.getY1())
                        g.drawString(getName(), drawing.getX1()+2, drawing.getY1()+5);
                    else g.drawString(getName(), drawing.getX1()+2, drawing.getY1()-1);
                }
            }
        }
        Util.restoreGraphics(g);
    }

    private boolean writeName(Coords drawing, ArrayList<Coords> all){
        Iterator iter = all.iterator();
        while(iter.hasNext()) {
            Coords cur = (Coords)iter.next();
            if(cur.getX1()==cur.getX2() &&
                drawing.getY1()==drawing.getY2() &&
                (drawing.getX1()==cur.getX1() || drawing.getX2()==cur.getX2()) &&
                ((cur.getY1()>cur.getY2() && ((cur.getY1()>=drawing.getY1() && cur.getY2()<=drawing.getY1()))) ||
                (cur.getY1()<cur.getY2() && ((cur.getY1()<=drawing.getY1() && cur.getY2()>=drawing.getY1())))))
                return false;
            if(cur.getY1()==cur.getY2() &&
                drawing.getX1()==drawing.getX2() &&
                (drawing.getY1()==cur.getY1() || drawing.getY2()==cur.getY2()) &&
                ((cur.getX1()>cur.getX2() && ((cur.getX1()>=drawing.getX1() && cur.getX2()<=drawing.getX1()))) ||
                (cur.getX1()<cur.getX2() && ((cur.getX1()<=drawing.getX1() && cur.getX2()>=drawing.getX1())))))
                return false;
        }
        return true;
    }

    public void setCoordsRelativeTo(ImageObserver observer, GSignal signal, int spacing){
        boolean start = true;
        boolean alterX = false;
        boolean alterY = false;
        Coords temp = new Coords();
        Iterator iter = signal.coords.keySet().iterator();
        while(iter.hasNext()){
            temp.setAll((Coords)iter.next());
            if(start && (Math.abs(temp.getX2() - temp.getX1()) > Math.abs(temp.getY2() - temp.getY1()))) alterY = true;
            if(start && (Math.abs(temp.getY2() - temp.getY1()) > Math.abs(temp.getX2() - temp.getX1()))) alterX = true;
            if(alterY){
                temp.alterY1(spacing);
                temp.alterY2(spacing);
            }
            else if(alterX){
                temp.alterX1(spacing);
                temp.alterX2(spacing);
            }
            addCoords(observer, temp);
        }
    }
}

